/*  1 验证是否登录，如果没有登陆则携带returnUrl跳转到登录界面,添加相应拦截器，响应401则跳转登录。
    2 获取服务器购物车数据。2.1 判断服务器响应状态，如果status!=200则return，如果code!=1则跳转登录页
      2.2将购物车数据渲染到页面，其中goodsId需要给商品的html添加dataset属性保存，同时获取商品选中状态给checkbox
      2.3 断是否所有商品的选中状态都为true，如果是则全选选中，否则全选不选中。
      2.4 调用计算总价和数量的函数。
    3 绑定事件的方法bindEve。 3.1绑定全选按钮点击事件。
      3.2点击全选时单选按钮状态跟随全选并调用计算数量和总价函数，发送请求修改服务器所有商品的选中状态跟随全选按钮
      3.3绑定商品数量input框输入数量事件，对商品数量进行更改，如果不是整数更改为整数，
       商品数量最小为1，同时对单个商品总价和所有选中商品总价进行更改。进入4.2.1
    4 购物车商品列表事件委托方法。 
      4.1如果点击的是单个商品选择框，则判定全选按钮状态并重新计算购物车总价和总数,发送请求修改单个商品的选中状态
         调用计算总价和数量的函数。
      4.2如果点击的是数量加减，则对商品数量进行更改，同时对单个商品总价和所有选中商品总价进行更改，价格保留2位小数
        4.2.1发送请求更改服务器商品数量，当超过库存时，提示库存不足，并更改数量为最大库存。
      4.3如果点击的是删除，则弹出确认删除选择框
         如果点击的是确认，则删除页面中此条数据，删除服务器数据，重新计算总价和全选状态，提示删除成功。
         (当删除后商品为0时，需要单独设置总价为0，并且显示“空空如也”)
         如果点击的是取消，则隐藏确认删除选择框。
*/

class Cart {
  constructor() {
    this.axiosRes();
    this.checkLogin();
    this.getData();
    this.bindEve();
  }
  axiosRes() {
    // 添加响应拦截器
    axios.interceptors.response.use(
      function (response) {
        // 对响应数据做点什么
        // console.log(response);
        if (response.data.code == 401) {
          location.assign("./login.html?returnUrl=./cart.html");
        }
        return response;
      },
      function (error) {
        // 对响应错误做点什么
        return Promise.reject(error);
      }
    );
  }
  /*************  1验证登录状态 **************/
  checkLogin() {
    let token = localStorage.getItem("token");
    // console.log(token);
    //判断是否有登录
    if (!token) location.assign("./login.html?returnUrl=./cart.html");
  }
  /*********3绑定事件的方法********/
  bindEve() {
    //全选按钮绑定事件
    this.$(".checkAll").addEventListener("click", this.allCheck.bind(this));
    //购物车商品列表事件委托方法
    this.$(".table .goods").addEventListener("click", this.dispatch.bind(this));
    //input框更改数量事件
    this.$(".goods ").addEventListener("input", this.changeNum.bind(this));
  }
  dispatch(eve) {
    let tar = eve.target;
    // 如果点击的是商品选择框
    if (tar.classList.contains("goods-checkbox")) this.setOneCheck(tar);
    //更改数量的方法
    if (tar.classList.contains("add") || tar.classList.contains("sub"))
      this.changeNum(eve);
    //删除商品的方法
    if (tar.classList.contains("del")) this.goodsDel(tar);
  }
  /********2获取服务器购物车数据*********/
  async getData() {
    let token = localStorage.getItem("token");
    // 设置请求头
    axios.defaults.headers.common["authorization"] = token;
    let user_id = localStorage.getItem("user_id");
    let { status, data } = await axios.get(
      "http://localhost:8888/cart/list?id=" + user_id
    );
    // console.log(data);
    if (status != 200) return;
    //判断登陆是否过期
    if (data.code != 1) location.assign("login.html?returnUrl=cart.html");
    // console.log(data);
    //判断购物车是否有数据，没有数据则显示‘空空如也’
    if (data.cart.length == 0) {
      this.$(".goOn").style.display = "block";
      return;
    }
    let html = "";
    // 遍历购物车数据，循环添加到页面中
    data.cart.forEach((ele) => {
      //因为行内设置添加checked属性，不论属性为true或false，都为选中状态，所以需要判定。
      let checked = "";
      if (ele.is_select) {
        checked = "checked";
      }
      //   console.log(ele.title, ele.price * ele.cart_number);
      html += `<div class="th" data-goodsid="${ele.goods_id}" data-goodsnum="${
        ele.goods_number
      }">
      <div class="pro clearfix">
          <label class="fl">
              <input type="checkbox" class="goods-checkbox" ${checked}/>
              <span></span>
          </label>
          <a class="fl" href="#">
              <dl class="clearfix">
                  <dt class="fl"><img src="${ele.img_small_logo}"></dt>
                  <dd class="fl">
                      <p>${ele.title}</p>
                      <p>颜色分类:</p>
                      <p>********</p>
                  </dd>
              </dl>
          </a>
      </div>
      <div class="price">￥${ele.price}</div>
      <div class="number">
          <p class="num clearfix">
              <img class="fl sub" src="img/temp/sub.jpg">
              <input class="fl" type="text" value="${ele.cart_number}"></input>
              <img class="fl add" src="img/temp/add.jpg">
          </p>
      </div>
      <div class="price sAll">￥${(ele.price * ele.cart_number).toFixed(
        2
      )}</div>
      <div class="price"><a class="del" href="#2">删除</a></div>
  </div>`;
    });
    // console.log(html, this.$(".table"));
    this.$(".table ul").innerHTML = html;
    //判断是否所有商品的选中状态都为true，如果是则全选选中，否则全选不选中。
    let flag = data.cart.every((ele) => ele.is_select == true);
    // console.log(flag);
    this.$(".checkAll").checked = flag;
    this.totalNP();
  }
  /********3.1全选按钮的点击事件*********/
  allCheck(eve) {
    //获取全选按钮的状态
    let status = eve.target.checked;
    //把全选按钮的状态设置给单个商品的按钮
    // this.setOneCheck(status);
    // 设置请求头编码格式
    axios.defaults.headers["Content-Type"] =
      "application/x-www-form-urlencoded";
    //设置请求头携带token
    let token = localStorage.getItem("token"); //获取token
    axios.defaults.headers.common["authorization"] = token; //携带token
    let user_id = localStorage.getItem("user_id"); //获取登录用户id
    let param = `id=${user_id}&type=${Number(status)}`;
    axios
      .post("http://localhost:8888/cart/select/all", param)
      .then(({ data, status }) => {
        //判断状态
        if (status != 200) {
          layer.msg("请刷新");
          return;
        }
        if (data.code != 1)
          location.assign("./login.html?returnUrl=./cart.html"); //如果登录状态异常跳转
        // console.log(status, data);
      });

    //获取所有单个商品的选择按钮节点
    let oneGoods = this.$("ul input[type='checkbox']");
    // console.log(oneGoods);
    //判断购物车商品数量如果大于1
    if (oneGoods.length > 1) {
      // 设置单个商品按钮状态跟随全选按钮
      oneGoods.forEach((ele) => {
        ele.checked = status;
      });
    } else {
      //如果等于1则直接设置
      oneGoods.checked = status;
    }
    // console.log(status);
    //计算总价和数量
    this.totalNP();
  }
  //*************4.1点击单选按钮事件
  setOneCheck(tar) {
    // console.log(tar.checked);
    // 设置请求头编码格式
    axios.defaults.headers["Content-Type"] =
      "application/x-www-form-urlencoded";
    //设置请求头携带token
    let token = localStorage.getItem("token");
    axios.defaults.headers.common["authorization"] = token;
    let user_id = localStorage.getItem("user_id");
    let goods_id = tar.parentNode.parentNode.parentNode.dataset.goodsid;
    let param = `id=${user_id}&goodsId=${goods_id}`;
    axios
      .post("http://localhost:8888/cart/select", param)
      .then(({ data, status }) => {
        //判断状态
        if (status != 200) {
          layer.msg("请刷新页面");
          return;
        }
        //如果登录失效则跳转
        if (data.code != 1)
          location.assign("./login.html?returnUrl=./cart.html");
        // console.log(status, data);
      });
    //当点击的是单个商品选择框，则判定全选按钮状态
    this.manageCB();
    //计算数量和总价
    this.totalNP();
  }
  //**************4.2更改商品数量的方法 */
  changeNum(eve) {
    if (eve.target.classList.contains("goods-checkbox")) return; //如果input是商品的选择框，则返回。
    let num = "";
    //如果点击的是数量＋
    if (eve.target.classList.contains("add")) {
      let value = eve.target.previousElementSibling.value; //获取数量
      num = +value + 1; //商品数量加1
      eve.target.previousElementSibling.value = num;
      let price =
        eve.target.parentNode.parentNode.previousElementSibling.innerHTML.split(
          "￥"
        )[1]; //获取单个商品单价
      eve.target.parentNode.parentNode.nextElementSibling.innerHTML = `￥${(
        price * num
      ).toFixed(2)}`; //计算单个商品总价
    } else if (eve.target.classList.contains("sub")) {
      //如果点击的是数量-
      let value = eve.target.nextElementSibling.value; //获取数量
      if (+value - 1 < 1) {
        value = 2;
      } //如果数量小于1则更改为1
      num = +value - 1; //商品数量-1
      eve.target.nextElementSibling.value = num;
      let price =
        eve.target.parentNode.parentNode.previousElementSibling.innerHTML.split(
          "￥"
        )[1]; //获取单个商品单价
      eve.target.parentNode.parentNode.nextElementSibling.innerHTML = `￥${(
        price * num
      ).toFixed(2)}`; //计算单个商品总价
    } else if (eve.type == "input") {
      if (+eve.target.value < 1 || isNaN(+eve.target.value)) {
        eve.target.value = 1;
      }
      eve.target.value = Math.floor(+eve.target.value);
      // console.log(+eve.target.value);
      num = +eve.target.value;
      let price =
        eve.target.parentNode.parentNode.previousElementSibling.innerHTML.split(
          "￥"
        )[1]; //获取单个商品单价
      eve.target.parentNode.parentNode.nextElementSibling.innerHTML = `￥${(
        price * num
      ).toFixed(2)}`; //计算单个商品总价
    }
    let goodsid = eve.target.parentNode.parentNode.parentNode.dataset.goodsid; //获得点击商品id
    this.sendGoodsNum(goodsid, num, eve); // 发送数据更改服务器商品数量
    this.totalNP(); //计算一次所有选中商品总价
  }
  //*发送请求更改服务器商品数量 */
  sendGoodsNum(goodsid, number, eve) {
    // 设置请求头编码格式
    axios.defaults.headers["Content-Type"] =
      "application/x-www-form-urlencoded";
    //设置请求头携带token
    let token = localStorage.getItem("token"); //获取token
    axios.defaults.headers.common["authorization"] = token; //携带token
    let user_id = localStorage.getItem("user_id");
    let param = `id=${user_id}&goodsId=${goodsid}&number=${number}`;
    axios
      .post("http://localhost:8888/cart/number", param)
      .then(({ data, status }) => {
        if (status != 200) {
          layer.msg("请刷新");
          return;
        }
        if (data.code != 1) {
          layer.msg("超出最大库存");
          let maxNum =
            +eve.target.parentNode.parentNode.parentNode.dataset.goodsnum;
          // console.log(maxNum);
          eve.target.parentNode.children[1].value = maxNum;
        }
      });
  }
  //**************4.3删除商品的方法 */
  goodsDel(tar) {
    //点击删除时，使确认删除框显示
    let tipDel = this.$(".tipDel");
    tipDel.style.display = "block";
    // 点击确认时，开始进行删除数据处理
    this.$("#cer").onclick = function () {
      tipDel.style.display = "none"; //让确认删除框关闭
      let user_id = localStorage.getItem("user_id");
      // console.log(tar.parentNode.parentNode);
      let goods_id = tar.parentNode.parentNode.dataset.goodsid;
      let token = localStorage.getItem("token");
      // 设置请求头
      axios.defaults.headers.common["authorization"] = token;
      // let param=`id=${user_id}&goodsId=${goods_id}`
      //发送数据删除服务器商品数据
      axios
        .get("http://localhost:8888/cart/remove", {
          params: {
            id: user_id,
            goodsId: goods_id,
          },
        })
        .then(({ status, data }) => {
          if (status != 200 || data.code != 1) {
            layer.msg("删除失败");
            return;
          }
          tar.parentNode.parentNode.remove(); //删除页面中节点
          layer.msg("删除成功"); //提示删除成功
          this.manageCB();
          //判断删除时页面中是否只剩一条数据，如果是的话删除后显示空空如也并且让总价归零。
          let flag = document.querySelectorAll("ul .th").length;
          if (flag == 0) {
            this.$(".goOn").style.display = "block";
            this.$("#all").innerHTML = 0;
            return;
          }
          this.totalNP(); //重新计算总数量和总价
          //重新判定全选按钮状态
        });
    }.bind(this);
    //点击取消的时候，关闭确认删除框
    this.$("#cancel").onclick = function () {
      tipDel.style.display = "none";
    };
  }
  //当点击的是单个商品选择框或删除商品时，则判定全选按钮状态
  manageCB() {
    //获取商品选择框
    let oneGoods = this.$("ul input[type='checkbox']");
    let flag = "";
    //如果商品全部选中则flag为true
    if (oneGoods.length > 1) {
      flag = [...oneGoods].every((ele) => {
        return ele.checked == true;
      });
    } else {
      flag = oneGoods.checked;
    }

    //如果商品全部选中则全选按钮生效，否则不生效
    if (!flag) {
      this.$(".checkAll").checked = false;
    } else if (flag) {
      this.$(".checkAll").checked = true;
    }
  }

  /*********计算数量和价格的方法************/
  totalNP() {
    let tNum = 0;
    let tPrice = 0;
    let goodsList = this.$(".table .goods .th"); //获取每一条商品
    if (goodsList.length > 1) {
      [...goodsList].forEach((ele) => {
        //获取每条商品下面选择框的选中状态
        let checkbox = this.getChild(ele, "label input", "checked");
        //如果状态为选中
        if (checkbox) {
          //tNum为选中的所有商品的数量之和，tPrice为选中的商品的价格之和
          tNum += +this.getChild(ele, ".num input", "value"); //“+”将字符串转化为数字，
          tPrice += +this.getChild(ele, ".sAll ", "innerHTML").split("￥")[1];
        }
      });
    } else {
      // console.log(goodsList);
      //获取每条商品下面选择框的选中状态
      let checkbox = this.getChild(goodsList, "label input", "checked");
      //如果状态为选中
      if (checkbox) {
        //tNum为选中的所有商品的数量之和，tPrice为选中的商品的价格之和
        tNum += +this.getChild(goodsList, ".num input", "value"); //“+”将字符串转化为数字，
        tPrice += +this.getChild(goodsList, ".sAll ", "innerHTML").split(
          "￥"
        )[1];
      }
    }

    // console.log(tNum, tPrice);
    //将数量和总价显示在页面中
    this.$("#sl").innerHTML = tNum;
    this.$("#all").innerHTML = tPrice.toFixed(2);
  }
  //获取节点的方法************
  $(ele) {
    let res = document.querySelectorAll(ele);
    return res.length == 1 ? res[0] : res;
  }
  //获取父节点下的某个子节点的属性的值********
  getChild(father, child, attr = "value") {
    //value为attr的默认值
    return father.querySelector(child)[attr];
  }
}
new Cart();
